Курс "Глубокое обучение". Первый семестр

Домашнее задание. Сегментация изображений

Импортирование библиотек:


1.Для начала мы скачаем датасет: ADDI project.

  1. Разархивируем .rar файл.
  2. Обратите внимание, что папка PH2 Dataset images должна лежать там же где и ipynb notebook.

Это фотографии двух типов поражений кожи: меланома и родинки. В данном задании мы не будем заниматься их классификацией, а будем сегментировать их.

Стуктура датасета у нас следующая:

IMD_002/
    IMD002_Dermoscopic_Image/
        IMD002.bmp
    IMD002_lesion/
        IMD002_lesion.bmp
    IMD002_roi/
        ...
IMD_003/
    ...
    ...

Для загрузки датасета я предлагаю использовать skimage: skimage.io.imread()

Изображения имеют разные размеры. Давайте изменим их размер на $256\times256 $ пикселей. skimage.transform.resize() можно использовать для изменения размера изображений. Эта функция также автоматически нормализует изображения в диапазоне $[0,1]$.

Чтобы убедиться, что все корректно, мы нарисуем несколько изображений

Разделим наши 200 картинок на 100/50/50 для валидации и теста

PyTorch DataLoader

Реализация различных архитектур:

Ваше задание будет состоять в том, чтобы написать несколько нейросетевых архитектур для решения задачи семантической сегментации. Сравнить их по качеству на тесте и испробовать различные лосс функции для них.


SegNet [2 балла]

Encoder часть выполнена по аналогии с vgg16:

Определим SegNet:

Метрика

В данном разделе предлагается использовать следующую метрику для оценки качества:

$I o U=\frac{\text {target } \cap \text { prediction }}{\text {target } \cup{prediction }}$

Пересечение (A ∩ B) состоит из пикселей, найденных как в маске предсказания, так и в основной маске истины, тогда как объединение (A ∪ B) просто состоит из всех пикселей, найденных либо в маске предсказания, либо в целевой маске.

To clarify this we can see on the segmentation: alt text

And the intersection will be the following:

alt text

Функция потерь [1 балл]

Теперь не менее важным, чем построение архитектуры, является определение оптимизатора и функции потерь.

Функция потерь - это то, что мы пытаемся минимизировать. Многие из них могут быть использованы для задачи бинарной семантической сегментации.

Популярным методом для бинарной сегментации является бинарная кросс-энтропия, которая задается следующим образом:

$$\mathcal L_{BCE}(y, \hat y) = -\sum_i \left[y_i\log\sigma(\hat y_i) + (1-y_i)\log(1-\sigma(\hat y_i))\right].$$

где $y$ это таргет желаемого результата и $\hat y$ является выходом модели. $\sigma$ - это логистическая функция, который преобразует действительное число $\mathbb R$ в вероятность $[0,1]$.

Однако эта потеря страдает от проблем численной нестабильности. Самое главное, что $\lim_{x\rightarrow0}\log(x)=\infty$ приводит к неустойчивости в процессе оптимизации. Рекомендуется посмотреть следующее упрощение в Тарая функция эквивалентна и не так подвержена численной неустойчивости.

$$\mathcal L_{BCE} = \hat y - y\hat y + \log\left(1+\exp(-\hat y)\right).$$

Тренировка [1 балл]

Функция для обучения, представленная в задании

Функция для обучения, выбырающая лучшую модель на основе IOU на валидационной выборке:

Инференс [1 балл]

После обучения модели эту функцию можно использовать для прогнозирования сегментации на новых данных:

Основной момент: обучение

Обучите вашу модель. Обратите внимание, что обучать необходимо до сходимости. Если указанного количества эпох (20) не хватило, попробуйте изменять количество эпох до сходимости алгоритма. Сходимость определяйте по изменению функции потерь на валидационной выборке.  С параметрами оптимизатора можно спокойно играть, пока вы не найдете лучший вариант для себя.

Процесс обучения всех моделей был выполнен на kaggle при 100 эпохах:

Функция для сохранения модели и истории:


Дополнительные функции потерь [2 балла]

В данном разделе вам потребуется имплементировать две функции потерь: DICE и Focal loss. Если у вас что-то не учится, велика вероятность, что вы ошиблись или учите слишком мало, прежде чем бить тревогу попробуйте поперебирать различные варианты, убедитесь, что во всех других сетапах сетть достигает желанного результата. СПОЙЛЕР: учиться она будеет при всех лоссах предложенных в этом задании.

1. Dice coefficient: Учитывая две маски $X$ и $Y$, общая метрика для измерения расстояния между этими двумя масками задается следующим образом:

$$D(X,Y)=\frac{2|X\cap Y|}{|X|+|Y|}$$

Эта функция не является дифференцируемой, но это необходимое свойство для градиентного спуска. В данном случае мы можем приблизить его с помощью:

$$\mathcal L_D(X,Y) = 1-\frac{1}{256 \times 256} \times \sum_i\frac{2X_iY_i}{X_i+Y_i}.$$

Не забудьте подумать о численной нестабильности, возникаемой в математической формуле.

Проводим тестирование:

2. Focal loss:

Окей, мы уже с вами умеем делать BCE loss:

$$\mathcal L_{BCE}(y, \hat y) = -\sum_i \left[y_i\log\sigma(\hat y_i) + (1-y_i)\log(1-\sigma(\hat y_i))\right].$$

Проблема с этой потерей заключается в том, что она имеет тенденцию приносить пользу классу большинства (фоновому) по отношению к классу меньшинства ( переднему). Поэтому обычно применяются весовые коэффициенты к каждому классу:

$$\mathcal L_{wBCE}(y, \hat y) = -\sum_i \alpha_i\left[y_i\log\sigma(\hat y_i) + (1-y_i)\log(1-\sigma(\hat y_i))\right].$$

Традиционно вес $\alpha_i$ определяется как обратная частота класса этого пикселя $i$, так что наблюдения миноритарного класса весят больше по отношению к классу большинства.

Еще одним недавним дополнением является взвешенный пиксельный вариант, которая взвешивает каждый пиксель по степени уверенности, которую мы имеем в предсказании этого пикселя.

$$\mathcal L_{focal}(y, \hat y) = -\sum_i \left[\left(1-\sigma(\hat y_i)\right)^\gamma y_i\log\sigma(\hat y_i) + (1-y_i)\log(1-\sigma(\hat y_i))\right].$$

Зафиксируем значение $\gamma=2$.



[BONUS] Мир сегментационных лоссов [5 баллов]

See a useful repo with losses for image segmentation

seglosses

В данном блоке предлагаем вам написать одну функцию потерь самостоятельно. Для этого необходимо прочитать статью и имплементировать ее. Кроме того провести численное сравнение с предыдущими функциями. Какие варианты?

1) Можно учесть Total Variation 2) Lova 3) BCE но с Soft Targets (что-то типа label-smoothing для многослассовой классификации) 4) Любой другой

Так как Тверский лосс очень похож на данные выше, то за него будет проставлено только 3 балла (при условии, если в модели нет ошибок при обучении). Постарайтесь сделать что-то интереснее.

Имплементация Hausdorff loss (статья):

Assymetric loss (статья):


U-Net [2 балла]

U-Net это архитектура нейронной сети, которая получает изображение и выводит его. Первоначально он был задуман для семантической сегментации (как мы ее будем использовать), но он настолько успешен, что с тех пор используется в других контекстах. Учитывая медицинское изображение, он выводит изображение в оттенках серого, представляющее вероятность того, что каждый пиксель является интересующей областью.

У нас в архитектуре все так же существует енкодер и декодер, как в SegNet, но отличительной особеностью данной модели являются skip-conenctions. Элементы соединяющие части декодера и енкодера. То есть для того чтобы передать на вход декодера тензор, мы конкатенируем симметричный выход с энкодера и выход предыдущего слоя декодера.

Новая модель путем изменения типа пулинга:

Max-Pooling for the downsampling and nearest-neighbor Upsampling for the upsampling.

Down-sampling:

    conv = nn.Conv2d(3, 64, 3, padding=1)
    pool = nn.MaxPool2d(3, 2, padding=1)

Up-Sampling

    upsample = nn.Upsample(32)
    conv = nn.Conv2d(64, 64, 3, padding=1)

Замените max-pooling на convolutions с stride=2 и upsampling на transpose-convolutions с stride=2.

Сделайте вывод какая из моделей лучше

Отчет (6 баллов):

Ниже предлагается написать отчет о проделанно работе и построить графики для лоссов, метрик на валидации и тесте. Если вы пропустили какую-то часть в задании выше, то вы все равно можете получить основную часть баллов в отчете, если правильно зададите проверяемые вами гипотезы.

Аккуратно сравните модели между собой и соберите наилучшую архитектуру. Проверьте каждую модель с различными лоссами. Мы не ограничиваем вас в формате отчета, но проверяющий должен отчетливо понять для чего построен каждый график, какие выводы вы из него сделали и какой общий вывод можно сделать на основании данных моделей. Если вы захотите добавить что-то еще, чтобы увеличить шансы получения максимального балла, то добавляйте отдельное сравнение.

Дополнительные комментарии:

Пусть у вас есть N обученных моделей.

Советы: попробуйте правильно поставить вопрос на который вы себе отвечаете и продемонстрировать таблицу/график, помогающий проверяющему увидеть ответ на этот вопрос. Пример: Ваня хочет узнать, с каким из 4-х лоссов модель (например, U-Net) имеет наилучшее качество. Что нужно сделать Ване? Обучить 4 одинаковых модели с разными лосс функциями. И измерить итогововое качество. Продемонстрировать результаты своих измерений и итоговый вывод. (warning: конечно же, это не идеально ответит на наш вопрос, так как мы не учитываем в экспериментах возможные различные типы ошибок, но для первого приближения этого вполне достаточно).

Примерное время на подготовку отчета 1 час, он содержит сравнеение метрик, график лоссов, выбор лучших моделей из нескольких кластеров и выбор просто лучшей модели, небольшой вывод по всему дз, возможно сравнение результирующих сегментаций, времени или числа параметров модели, проявляйте креативность.

Функции для удобства оценки моделей:

Посмотрим на SegNet модели:

Видим, что на валидационной выборке лучше всего посказала себя SegNet с BCE лоссом, переступив порог 0.8, на тестовой выборке заначение IOU сравнимо с моделью с focal_loss. C dice loss SegNet показала себя плохо.

Посмотрим на UNet модели:

UNet показал сравнимые скоры IOU на BCE, Dice, Focal как на валидационной ~0.8, так и на тестовой выборке. С Asym loss Unet показала себя плохо, не превысив 0.5 IOU.

Посмотрим на UNet2 модели:

UNet2 модели показали лучшие скоры чем Unet при BCE и Focal loss

Выберем модели разных архитектур с лучшими лоссами

Среди этих моделей лучше всего на валидационной выборке показывала себя модель UNet2 с BCE loss. Также она показала отличный скор IOU на тестовой выборке. Все модели были обучены на Kaggle при 100 эпохах, batch_size=5. Т.к признаков сильного переобучения у данной модели при 100 эпохах не наблюдается, обучим её при большем количестве.

При 400 эпохах:

Видно, что при >150 эпохах модель начинает переобучаться. Скор модели, остановленной train_model() на тестовой выборке: